package com.wyclabs.commons.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;

import java.util.HashMap;
import java.util.Map;

/**
 * @author YichuanWang
 * @date 2019/04/22
 * @description bean工具扩展
 */
@Slf4j
public class BeanUtils {

    private static Map<String, BeanCopier> copierCache = new HashMap<>(20);

    /**
     * BeanCopy
     * @param origin 原对象
     * @param target 目标Class
     * @return 若原对象为null，则返回的对象为所有field均为null的空对象
     */
    public static <T> T generateAndCopy(Object origin, Class<T> target) {
        T res = buildTarget(target);
        copyProperties(origin, res);
        return res;
    }

    /**
     * BeanCopy
     * @param origin 原对象
     * @param target 目标Class
     */
    public static void copyProperties(Object origin, Object target) {
        String beanKey = generateKey(origin.getClass(), target.getClass());
        BeanCopier copier = copierCache.get(beanKey);
        if (copier == null) {
            copier = BeanCopier.create(origin.getClass(), target.getClass(), false);
            copierCache.put(beanKey, copier);
        }
        copier.copy(origin, target, null);
    }

    /**
     * BeanCopy
     * @param origin 原对象
     * @param target 目标Class
     * @return 若原对象为null，则返回也为null
     */
    public static <T> T copy(Object origin, Class<T> target) {
        if (origin == null) {
            return null;
        }
        return generateAndCopy(origin, target);
    }

    /**
     * BeanCopy - 忽视null字段
     * @param origin 原对象，若其field为null，则不会对该field进行copy
     * @param target 目标对象
     */
    public static void copyIgnoreNull(Object origin, Object target) {
        BeanUtil.copyProperties(origin, target, CopyOptions.create().setIgnoreNullValue(Boolean.TRUE));
    }

    /**
     * 构建Target对象
     */
    private static <T> T buildTarget(Class<T> dest) {
        T res = null;
        try {
            res = dest.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        return res;
    }

    private static String generateKey(Class srcClazz, Class targetClazz) {
        return srcClazz.toString() + targetClazz.toString();
    }
}
